






/*--------------------------------------介绍信号量--------------------------------------*/
/*
*  基于消息队列(循环队列)的生产者消费者模型的一般写法:
*
// 生产者
void Push(const T& in){
	// ?: 这个代码 有没有优化的可能
	// 你认为：现加锁，后申请信号量，还是现申请信号量，在加锁？
	P(_spaceSem); // 申请到了空间信号量，意味着，我一定能进行正常的生产
	pthread_mutex_lock(&_pmutex);
	_queue[_productorStep++] = in;
	_productorStep %= _cap;
	pthread_mutex_unlock(&_pmutex);
	V(_dataSem);
}
// 消费者
void Pop(T* out){
	// 你认为：现加锁，后申请信号量，还是现申请信号量，在加锁？
	P(_dataSem);
	pthread_mutex_lock(&_cmutex);
	*out = _queue[_consumerStep++];
	_consumerStep %= _cap;
	pthread_mutex_unlock(&_cmutex);
	V(_spaceSem);
}
*/

/*--------------------------------    条件变量实现    -----------------------------------*/
//condition_variable
//while (true){
//	lock();
//	if (条件满足){
//		doSomething();
//	}
//	unlock();
//}

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>

#include <Windows.h>  // Sleep() 函数的头文件
#include <thread>
#include <mutex>
#include <condition_variable>

using namespace std;

const int SIZE_OF_BUFFER = 4;            //缓冲区长度
int g_buffer[SIZE_OF_BUFFER];            //缓冲区是个循环队列
int buffer_size = 0;  // 开始空的

int ProductID = 0;                       //产品号
int ConsumeID = 0;                       //将被消耗的产品号
int in = 0;                              //产品进缓冲区时的缓冲区下标
int out = 0;                             //产品出缓冲区时的缓冲区下标

//mutex g_Mutex;                          //公有互斥锁，用于线程间的互斥
//两个 mutex 再配合 Sleep 才有什么现象 ？
mutex gProducer_Mutex;
mutex gConsumer_Mutex;
condition_variable g_Producer;			//生产者的条件变量，当缓冲区满时迫使生产者等待
condition_variable g_Consumer;			//消费者的条件变量，当缓冲区空时迫使消费者等待
//condition_variable 和 mutex 是配合使用的
//unique_lock<mutex> lock(g_hMutex);
//g_ConsumerSemaphore.wait(lock);     wait 函数参数必有一个 unique_lock 类型的变量

// 得知道循环队列 
// 得知道Sleep的作用

//生产者
void* Producer(void* p) {
	//Returns the thread id.
	std::thread::id main_thread_id = std::this_thread::get_id();

	for(;;) {
		if (buffer_size < SIZE_OF_BUFFER) 
		{
			//unique_lock<mutex> lock(g_Mutex);
			unique_lock<mutex> lock(gProducer_Mutex);
			g_Producer.wait(lock);

			cout << "生产者线程 " << main_thread_id << " 请求生产." << endl;
			cout << "生产者线程 " << main_thread_id << " 请求独占缓冲区." << endl;

			//操作等待
			//Sleep(1);
			//生产一个产品
			cout << "生产者线程 " << main_thread_id << " 生产 " << ++ProductID << " 号产品成功." << endl;
			cout << "生产者线程 " << main_thread_id << " 请求将产品 " << ProductID << " 投入缓冲区." << endl;
			//把新生产的产品放入缓冲区
			g_buffer[in] = ProductID;
			in = (in + 1) % SIZE_OF_BUFFER;
			buffer_size++;

			//操作等待
			//Sleep(1);   
			cout << "生产者线程 " << main_thread_id << " 将产品 " << ProductID << " 投入缓冲区中成功." << endl;

			//输出缓冲区当前的状态
			cout << "----------------------------------" << endl
				<< "\n当前缓冲区情况如图(■代表已有产品，□代表没有产品):   " << endl;
			for (int i = 0; i < SIZE_OF_BUFFER; ++i) {
				if (g_buffer[i] != 0)
					cout << "■";
				else
					cout << "□";
			}
			cout << "\n\n------------------------------\n" << endl;
		}

		g_Consumer.notify_one();
	}

	return nullptr;
}


//消费者
void* Consumer(void* p) {
	//Returns the thread id.
	std::thread::id main_thread_id = std::this_thread::get_id();

	while (1) {
		if (buffer_size != 0) 
		{
			//unique_lock<mutex> lock(g_Mutex);
			unique_lock<mutex> lock(gConsumer_Mutex);
			g_Consumer.wait(lock);

			//延迟等待
			Sleep(1); 
			//从缓冲区中取出一个产品
			cout << "消费者线程 " << main_thread_id << " 请求取出一个产品." << endl;
			ConsumeID = g_buffer[out];
			g_buffer[out] = 0;
			out = (out + 1) % SIZE_OF_BUFFER;
			buffer_size--;

			cout << "消费者线程 " << main_thread_id << " 取出产品 " << ConsumeID << " 成功." << endl;

			//消耗一个产品
			cout << "消费者线程 " << main_thread_id << " 开始消费消费产品 " << ConsumeID << "." << endl;
			Sleep(1);
			cout << "消费者线程 " << main_thread_id << " 消费产品 " << ConsumeID << " 成功." << endl;

			//输出缓冲区当前的状态
			cout << "----------------------------------" << endl
				<< "\n当前缓冲区情况如图:   " << endl;
			for (int i = 0; i < SIZE_OF_BUFFER; ++i) {
				if (g_buffer[i] != 0)
					cout << "■";
				else  cout << "□";
			}
			cout << "\n\n------------------------------\n" << endl;
		}

		g_Producer.notify_one();
	}

	return nullptr;
}

int main() {
	cout << "\n==================生产者-消费者 模拟==================\n" << endl;
	const int thread_cnt = 6;
	thread threads[thread_cnt];

	cout << "系统开始模拟，并自动生成模拟数据..." << endl;
	system("pause"); //暂停确认开始执行
	cout << "线程总数：" << thread_cnt << endl;
	// 前3个为生产者线程
	// 后3个为消费者线程
	for (int i = 0; i < thread_cnt; i++) {
		if (i < 4) threads[i] = thread(Producer, &i);
		else threads[i] = thread((Consumer), &i);
	}

	cout << "系统模拟结束..." << endl;

	// 回收子线程
	for (auto& th : threads)
		th.join();

	return 0;
}

